package com.zxjbyte.yiyi.module.upms.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.zxjbyte.yiyi.framework.common.constant.RedisKeyDefine;
import com.zxjbyte.yiyi.framework.common.constant.StatusConstant;
import com.zxjbyte.yiyi.framework.redis.manager.RedisDaoHolder;
import com.zxjbyte.yiyi.module.upms.context.properties.CaptchaProperties;
import com.zxjbyte.yiyi.module.upms.domain.vo.CaptchaVO;
import com.zxjbyte.yiyi.module.upms.service.CaptchaService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 基于HttpSession的方式：
 * 在单体应用或需要基于用户会话状态的场景下，使用Session存储验证码是一个简单有效的方式
 *
 * 可改造成基于Redis等存储的方式
 *
 * @Author zhangxingjia
 * @Date 2024/8/13 17:05
 * @Version: 1.0
 */
@Service
public class CaptchaServiceImpl implements CaptchaService {

    @Resource
    private CaptchaProperties properties;

    @Override
    public CaptchaVO generateCaptcha() {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(properties.getWidth(), properties.getHeight(), getCodeGenerator(), properties.getLineCount());
        CaptchaVO vo = new CaptchaVO();
        vo.setCaptchaUUID(IdUtil.fastUUID());
        vo.setCaptchaCode(lineCaptcha.getCode());
        vo.setCaptchaImage(lineCaptcha.getImageBase64Data());
        // 验证码缓存redis一分钟
        RedisDaoHolder.getRedisDao().setEx(getRedisKey(vo.getCaptchaUUID()), vo.getCaptchaCode(), 60L);
        return vo;
    }

    @Override
    public int verify(String uuid, String inputCode) {
        String redisKey = getRedisKey(uuid);
        // Retrieve the stored captcha from Redis
        String storedCode = RedisDaoHolder.getRedisDao().get(redisKey);
        if(storedCode == null){
            return StatusConstant.EXPIRE;
        }
        if (getCodeGenerator().verify(storedCode, inputCode)) {
            // If the captcha is valid, remove it from Redis to prevent reuse
            RedisDaoHolder.getRedisDao().del(redisKey);
            return StatusConstant.SUCCESS;
        }
        return StatusConstant.FAIL;
    }

    private String getRedisKey(String uuid) {
        return RedisKeyDefine.module(RedisKeyDefine.Modules.CAPTCHA).buildKey(uuid);
    }

    /**
     * 获取验证码生成器
     * @return 验证码生成器
     */
    private CodeGenerator getCodeGenerator() {
        return Singleton.get("codeGenerator", () -> {
            CodeGenerator codeGenerator;
            if(properties.getMode().equals(CaptchaProperties.CaptchaMode.MATH)){
                codeGenerator = new MathGenerator();
            } else {
                String baseStr = null;
                if(properties.getMode().equals(CaptchaProperties.CaptchaMode.RANDOM_CHAR_NUMBER)){
                    baseStr = RandomUtil.BASE_CHAR_NUMBER;
                } else if(properties.getMode().equals(CaptchaProperties.CaptchaMode.RANDOM_CHAR)){
                    baseStr = RandomUtil.BASE_CHAR.toUpperCase() + RandomUtil.BASE_CHAR;
                } else if(properties.getMode().equals(CaptchaProperties.CaptchaMode.RANDOM_NUMBER)){
                    baseStr = RandomUtil.BASE_NUMBER;
                }
                codeGenerator = new RandomGenerator(baseStr, properties.getCount());
            }
            return codeGenerator;
        });
    }
}
